﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using GameCreator.Core;
using Gp.Scripts.Database;
using PixelCrushers.DialogueSystem;
using QFramework;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Gp.Scripts.Core {
    public class SceneScriptEvent {
        public string Messages;

        public SceneScriptEvent(string messages) {
            Messages = messages;
        }
    }

    [Serializable]
    public class SceneScriptWrapper {
        [ValueDropdown("NameSpaceList")]
        public string nameSpace;

        [ValueDropdown("TitleList"),
         OnValueChanged("UpdateInfo")
        ]
        public string title;

        [ReadOnly] public string id;
        [ReadOnly] public string value;
        
        [TextArea]
        [LabelText("脚本描述")]
        [ReadOnly] public string description; 


#if UNITY_EDITOR
        private IEnumerable<string> NameSpaceList =>
            CharacterModelsDatabase.Instance.flowVariableNames.Select(x => x.nameSpace);

        private IEnumerable<string> TitleList => CharacterModelsDatabase.Instance.flowVariableNames
            .Where(x => x.nameSpace == nameSpace)
            .Select(x => x.title);

        [Button]
        private void UpdateInfo() {
            var wrapper = CharacterModelsDatabase.Instance.flowVariableNames
                .FirstOrDefault(x => x.title == title && x.nameSpace == nameSpace);
            if (wrapper == null) {
                id = "";
                value = "";
                description = "";
            }
            else {
                id = wrapper.id;
                value = wrapper.value;
                description = wrapper.description;
            }
        }
#endif
    }


    public class SceneScriptArchitecture : Architecture<SceneScriptArchitecture> {
        protected override void Init() { }
    }


    public class SceneScriptExecutor : MonoBehaviour, IController {
        public bool looseMode = false;
        [ShowIf("@looseMode")]public string looseModeId = "";
        
        [HideIf("@looseMode")][HideLabel] public SceneScriptWrapper sceneScript;
        [LabelText("对话结束后触发")]
        public bool waitingForConversationEnd = true;
        public List<Actions> actions;
        [HideInInspector]
        public bool executing = false;

        private void Start() {
            this.RegisterEvent<SceneScriptEvent>(args => {
                if (GetId() != args.Messages) return;
                StartCoroutine(Execute());
            }).UnRegisterWhenGameObjectDestroyed(gameObject);
        }


        private IEnumerator Execute() {
            //开始对话的时候锁住 跳过对话
            // Global.Get<GUIManager>().DisableDialogueSkip();
            
            //如果要求对话结束之后执行，挂起
            while (waitingForConversationEnd && DialogueManager.isConversationActive) {
                yield return 0;
            }
            

            //转为执行状态，表明还没有执行结束
            executing = true;
            
            //开始执行
            foreach (var action in actions.Where(action => action)) {
                action.Execute(gameObject);
            }

            StartCoroutine(CallBack());
        }

        private IEnumerator CallBack() {
            //如果还在执行，就不解锁跳过
            while (executing) {
                var temp = false;
                
                //如果每个action都执行完毕，结束执行
                foreach (Actions action in actions) {
                    temp = temp || action.actionsList.isExecuting;
                }
                executing = temp;
                yield return 0;
            }
            
            //解锁执行
            // Global.Get<GUIManager>().EnableDialogueSkip();
        }


        private string GetId() {
            return looseMode ? looseModeId : sceneScript.value;
        }

        public IArchitecture GetArchitecture() {
            return SceneScriptArchitecture.Interface;
        }

#if UNITY_EDITOR
        [Button]
        private void FillAction() {
            actions.AddRange(this.GetComponentsInChildren<Actions>());
        }


        [Button]
        private void AddAction() {
            var o = new GameObject("Action");
            o.transform.SetParent(transform);
            actions.Add(o.AddComponent<Actions>());
        }
#endif
    }
}